{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Synthetic data examples"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this Notebook we will build synthetic data suitable to Alphalens analysis. This is useful to understand how Alphalens expects the input to be formatted and also it is a good testing environment to experiment with Alphalens."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "    \n",
    "from numpy import nan\n",
    "from pandas import (DataFrame, date_range)\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "from alphalens.tears import (create_returns_tear_sheet,\n",
    "                      create_information_tear_sheet,\n",
    "                      create_turnover_tear_sheet,\n",
    "                      create_summary_tear_sheet,\n",
    "                      create_full_tear_sheet,\n",
    "                      create_event_returns_tear_sheet,\n",
    "                      create_event_study_tear_sheet)\n",
    "\n",
    "from alphalens.utils import get_clean_factor_and_forward_returns"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "#\n",
    "# build price\n",
    "#\n",
    "price_index = date_range(start='2015-1-10', end='2015-2-28')\n",
    "price_index.name = 'date'\n",
    "tickers = ['A', 'B', 'C', 'D', 'E', 'F']\n",
    "data = [[1.0025**i, 1.005**i, 1.00**i, 0.995**i, 1.005**i, 1.00**i]\n",
    "        for i in range(1, 51)]\n",
    "prices = DataFrame(index=price_index, columns=tickers, data=data)\n",
    "\n",
    "#\n",
    "# build factor\n",
    "#\n",
    "factor_index = date_range(start='2015-1-15', end='2015-2-13')\n",
    "factor_index.name = 'date'\n",
    "factor = DataFrame(index=factor_index, columns=tickers,\n",
    "                   data=[[3, 4, 2, 1, nan, nan], [3, nan, nan, 1, 4, 2],\n",
    "                         [3, 4, 2, 1, nan, nan], [3, 4, 2, 1, nan, nan],\n",
    "                         [3, 4, 2, 1, nan, nan], [3, 4, 2, 1, nan, nan],\n",
    "                         [3, nan, nan, 1, 4, 2], [3, nan, nan, 1, 4, 2],\n",
    "                         [3, 4, 2, 1, nan, nan], [3, 4, 2, 1, nan, nan],\n",
    "                         [3, nan, nan, 1, 4, 2], [3, nan, nan, 1, 4, 2],\n",
    "                         [3, nan, nan, 1, 4, 2], [3, nan, nan, 1, 4, 2],\n",
    "                         [3, nan, nan, 1, 4, 2], [3, nan, nan, 1, 4, 2],\n",
    "                         [3, nan, nan, 1, 4, 2], [3, nan, nan, 1, 4, 2],\n",
    "                         [3, nan, nan, 1, 4, 2], [3, nan, nan, 1, 4, 2],\n",
    "                         [3, 4, 2, 1, nan, nan], [3, 4, 2, 1, nan, nan],\n",
    "                         [3, 4, 2, 1, nan, nan], [3, 4, 2, 1, nan, nan],\n",
    "                         [3, 4, 2, 1, nan, nan], [3, 4, 2, 1, nan, nan],\n",
    "                         [3, 4, 2, 1, nan, nan], [3, 4, 2, 1, nan, nan],\n",
    "                         [3, nan, nan, 1, 4, 2], [3, nan, nan, 1, 4, 2]]) \\\n",
    "    .stack()\n",
    "factor_groups = {'A': 'Group1', 'B': 'Group2', 'C': 'Group1', 'D': 'Group2', 'E': 'Group1', 'F': 'Group2'}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Axes: xlabel='date'>"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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5UpkZGTgwIED+PTTT5Gbmyte0WPgbj9rampq8Le//Q1ZWVkIDQ3F9evX8fOf/xx+fn647777RK5+FIi6l2eUHT16VABw25+tW7cKtbW1A14DIBw9elTs0kfdnb42giAIv/3tb4WYmBjBx8dHiIuLE1588UXBaDSKW/QYGOx7Yvfu3S737dq1S4iJiREUCoWQnp4uHDt2TJyCRfC73/1OiIuLE2QymbB48WKhuLhYEITBv6cACLW1teIWPUYG+9oIgiA8//zzQnh4uODj4yMkJiYKv/rVrwSbzSZitWPjbj9rBEEQ3nrrLSEhIUHw9fUV5syZI3z88cfiFTxG7vazpqGhQdi4caMQFhYm+Pj4CDExMcKXv/xloby8XNzCRwkPyiMiIiJRefSaESIiIhIfwwgRERGJimGEiIiIRMUwQkRERKJiGCEiIiJRMYwQERGRqBhGiIiISFQMI0RERCQqhhEiIiISFcMIERERiYphhIiIiETFMEJERESiYhghIiIiUTGMEBERkagYRoiIiEhUDCNEREQkKoYRIiIiEhXDCBEREYmKYYSIiIhExTBCREREomIYISIiIlExjBAREZGoGEaIiIhIVAwjRDQsEokEH3/8sdhlEJEbYRgh8kDbtm2DRCK57U91dbXYpRGRB/IWuwAiEseGDRuwe/dul8dCQ0NFqoaIPBlHRog8lFwuR0REhMsfLy8v7Nu3D/Pnz4evry+mTp2KV155BRaLxeW5TU1N2LhxI/z8/DB16lR88MEHIr0LInIHDCNE5HTs2DFs2bIF3/72t1FaWor//u//xp49e/DTn/7U5b6XXnoJjzzyCM6fP49//dd/xRe/+EWUlZWJVDURTXQSQRAEsYsgorG1bds2vPfee/D19XU+tnHjRnR2dmLt2rXYuXOn8/H33nsP3/ve99DY2AjAvoD1qaeewptvvum8Z8mSJZg/fz5+//vfj92bICK3wTUjRB4qIyPDJVAolUrMnj0bhYWFLiMhVqsVPT09MBgMUCgUAID09HSXz5Weno5z586NSd1E5H4YRog8lFKpREJCgstjOp0Or7zyCh5++OHb7u8/ikJENJIYRojIaf78+aioqLgtpNyquLgYW7Zscfl43rx5o10eEbkphhEicvrBD36ABx54AHFxcXj00UchlUpx/vx5XLp0CT/5yU+c9+3duxcLFy7E8uXL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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "prices.plot()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>A</th>\n",
       "      <th>B</th>\n",
       "      <th>C</th>\n",
       "      <th>D</th>\n",
       "      <th>E</th>\n",
       "      <th>F</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>date</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2015-01-10</th>\n",
       "      <td>1.002500</td>\n",
       "      <td>1.005000</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0.995000</td>\n",
       "      <td>1.005000</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2015-01-11</th>\n",
       "      <td>1.005006</td>\n",
       "      <td>1.010025</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0.990025</td>\n",
       "      <td>1.010025</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2015-01-12</th>\n",
       "      <td>1.007519</td>\n",
       "      <td>1.015075</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0.985075</td>\n",
       "      <td>1.015075</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2015-01-13</th>\n",
       "      <td>1.010038</td>\n",
       "      <td>1.020151</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0.980150</td>\n",
       "      <td>1.020151</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2015-01-14</th>\n",
       "      <td>1.012563</td>\n",
       "      <td>1.025251</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0.975249</td>\n",
       "      <td>1.025251</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                   A         B    C         D         E    F\n",
       "date                                                        \n",
       "2015-01-10  1.002500  1.005000  1.0  0.995000  1.005000  1.0\n",
       "2015-01-11  1.005006  1.010025  1.0  0.990025  1.010025  1.0\n",
       "2015-01-12  1.007519  1.015075  1.0  0.985075  1.015075  1.0\n",
       "2015-01-13  1.010038  1.020151  1.0  0.980150  1.020151  1.0\n",
       "2015-01-14  1.012563  1.025251  1.0  0.975249  1.025251  1.0"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "prices.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "date         \n",
       "2015-01-15  A    3.0\n",
       "            B    4.0\n",
       "            C    2.0\n",
       "            D    1.0\n",
       "2015-01-16  A    3.0\n",
       "            D    1.0\n",
       "            E    4.0\n",
       "            F    2.0\n",
       "2015-01-17  A    3.0\n",
       "            B    4.0\n",
       "dtype: float64"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "factor.head(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Dropped 0.0% entries from factor data: 0.0% in forward returns computation and 0.0% in binning phase (set max_loss=0 to see potentially suppressed Exceptions).\n",
      "max_loss is 35.0%, not exceeded: OK!\n"
     ]
    }
   ],
   "source": [
    "factor_data = get_clean_factor_and_forward_returns(\n",
    "    factor,\n",
    "    prices,\n",
    "    groupby=factor_groups,\n",
    "    quantiles=4,\n",
    "    periods=(1, 3), \n",
    "    filter_zscore=None)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th>1D</th>\n",
       "      <th>3D</th>\n",
       "      <th>factor</th>\n",
       "      <th>group</th>\n",
       "      <th>factor_quantile</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>date</th>\n",
       "      <th>asset</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th rowspan=\"4\" valign=\"top\">2015-01-15</th>\n",
       "      <th>A</th>\n",
       "      <td>0.0025</td>\n",
       "      <td>0.007519</td>\n",
       "      <td>3.0</td>\n",
       "      <td>Group1</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>B</th>\n",
       "      <td>0.0050</td>\n",
       "      <td>0.015075</td>\n",
       "      <td>4.0</td>\n",
       "      <td>Group2</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>C</th>\n",
       "      <td>0.0000</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>2.0</td>\n",
       "      <td>Group1</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>D</th>\n",
       "      <td>-0.0050</td>\n",
       "      <td>-0.014925</td>\n",
       "      <td>1.0</td>\n",
       "      <td>Group2</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th rowspan=\"4\" valign=\"top\">2015-01-16</th>\n",
       "      <th>A</th>\n",
       "      <td>0.0025</td>\n",
       "      <td>0.007519</td>\n",
       "      <td>3.0</td>\n",
       "      <td>Group1</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>D</th>\n",
       "      <td>-0.0050</td>\n",
       "      <td>-0.014925</td>\n",
       "      <td>1.0</td>\n",
       "      <td>Group2</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>E</th>\n",
       "      <td>0.0050</td>\n",
       "      <td>0.015075</td>\n",
       "      <td>4.0</td>\n",
       "      <td>Group1</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>F</th>\n",
       "      <td>0.0000</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>2.0</td>\n",
       "      <td>Group2</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th rowspan=\"2\" valign=\"top\">2015-01-17</th>\n",
       "      <th>A</th>\n",
       "      <td>0.0025</td>\n",
       "      <td>0.007519</td>\n",
       "      <td>3.0</td>\n",
       "      <td>Group1</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>B</th>\n",
       "      <td>0.0050</td>\n",
       "      <td>0.015075</td>\n",
       "      <td>4.0</td>\n",
       "      <td>Group2</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                      1D        3D  factor   group  factor_quantile\n",
       "date       asset                                                   \n",
       "2015-01-15 A      0.0025  0.007519     3.0  Group1                3\n",
       "           B      0.0050  0.015075     4.0  Group2                4\n",
       "           C      0.0000  0.000000     2.0  Group1                2\n",
       "           D     -0.0050 -0.014925     1.0  Group2                1\n",
       "2015-01-16 A      0.0025  0.007519     3.0  Group1                3\n",
       "           D     -0.0050 -0.014925     1.0  Group2                1\n",
       "           E      0.0050  0.015075     4.0  Group1                4\n",
       "           F      0.0000  0.000000     2.0  Group2                2\n",
       "2015-01-17 A      0.0025  0.007519     3.0  Group1                3\n",
       "           B      0.0050  0.015075     4.0  Group2                4"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "factor_data.head(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "Cannot perform min with non-ordered Categorical",
     "output_type": "error",
     "traceback": [
      "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m",
      "\u001B[0;31mTypeError\u001B[0m                                 Traceback (most recent call last)",
      "Cell \u001B[0;32mIn[18], line 1\u001B[0m\n\u001B[0;32m----> 1\u001B[0m create_full_tear_sheet(factor_data, long_short\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mFalse\u001B[39;00m, group_neutral\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mFalse\u001B[39;00m, by_group\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mFalse\u001B[39;00m)\n\u001B[1;32m      2\u001B[0m create_event_returns_tear_sheet(factor_data, prices, avgretplot\u001B[38;5;241m=\u001B[39m(\u001B[38;5;241m3\u001B[39m, \u001B[38;5;241m11\u001B[39m),\n\u001B[1;32m      3\u001B[0m                                 long_short\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mFalse\u001B[39;00m, group_neutral\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mFalse\u001B[39;00m, by_group\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mFalse\u001B[39;00m)\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/alphalens/plotting.py:45\u001B[0m, in \u001B[0;36mcustomize.<locals>.call_w_context\u001B[0;34m(*args, **kwargs)\u001B[0m\n\u001B[1;32m     43\u001B[0m     \u001B[38;5;28;01mwith\u001B[39;00m plotting_context(), axes_style(), color_palette:\n\u001B[1;32m     44\u001B[0m         sns\u001B[38;5;241m.\u001B[39mdespine(left\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mTrue\u001B[39;00m)\n\u001B[0;32m---> 45\u001B[0m         \u001B[38;5;28;01mreturn\u001B[39;00m func(\u001B[38;5;241m*\u001B[39margs, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n\u001B[1;32m     46\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[1;32m     47\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m func(\u001B[38;5;241m*\u001B[39margs, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/alphalens/tears.py:528\u001B[0m, in \u001B[0;36mcreate_full_tear_sheet\u001B[0;34m(factor_data, long_short, group_neutral, by_group)\u001B[0m\n\u001B[1;32m    497\u001B[0m \u001B[38;5;129m@plotting\u001B[39m\u001B[38;5;241m.\u001B[39mcustomize\n\u001B[1;32m    498\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mcreate_full_tear_sheet\u001B[39m(factor_data,\n\u001B[1;32m    499\u001B[0m                            long_short\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mTrue\u001B[39;00m,\n\u001B[1;32m    500\u001B[0m                            group_neutral\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mFalse\u001B[39;00m,\n\u001B[1;32m    501\u001B[0m                            by_group\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mFalse\u001B[39;00m):\n\u001B[1;32m    502\u001B[0m \u001B[38;5;250m    \u001B[39m\u001B[38;5;124;03m\"\"\"\u001B[39;00m\n\u001B[1;32m    503\u001B[0m \u001B[38;5;124;03m    Creates a full tear sheet for analysis and evaluating single\u001B[39;00m\n\u001B[1;32m    504\u001B[0m \u001B[38;5;124;03m    return predicting (alpha) factor.\u001B[39;00m\n\u001B[0;32m   (...)\u001B[0m\n\u001B[1;32m    525\u001B[0m \u001B[38;5;124;03m        If True, display graphs separately for each group.\u001B[39;00m\n\u001B[1;32m    526\u001B[0m \u001B[38;5;124;03m    \"\"\"\u001B[39;00m\n\u001B[0;32m--> 528\u001B[0m     plotting\u001B[38;5;241m.\u001B[39mplot_quantile_statistics_table(factor_data)\n\u001B[1;32m    529\u001B[0m     create_returns_tear_sheet(\n\u001B[1;32m    530\u001B[0m         factor_data, long_short, group_neutral, by_group, set_context\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mFalse\u001B[39;00m\n\u001B[1;32m    531\u001B[0m     )\n\u001B[1;32m    532\u001B[0m     create_information_tear_sheet(\n\u001B[1;32m    533\u001B[0m         factor_data, group_neutral, by_group, set_context\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mFalse\u001B[39;00m\n\u001B[1;32m    534\u001B[0m     )\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/alphalens/plotting.py:190\u001B[0m, in \u001B[0;36mplot_quantile_statistics_table\u001B[0;34m(factor_data)\u001B[0m\n\u001B[1;32m    188\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mplot_quantile_statistics_table\u001B[39m(factor_data):\n\u001B[1;32m    189\u001B[0m     quantile_stats \u001B[38;5;241m=\u001B[39m factor_data\u001B[38;5;241m.\u001B[39mgroupby(\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mfactor_quantile\u001B[39m\u001B[38;5;124m'\u001B[39m) \\\n\u001B[0;32m--> 190\u001B[0m         \u001B[38;5;241m.\u001B[39magg([\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mmin\u001B[39m\u001B[38;5;124m'\u001B[39m, \u001B[38;5;124m'\u001B[39m\u001B[38;5;124mmax\u001B[39m\u001B[38;5;124m'\u001B[39m, \u001B[38;5;124m'\u001B[39m\u001B[38;5;124mmean\u001B[39m\u001B[38;5;124m'\u001B[39m, \u001B[38;5;124m'\u001B[39m\u001B[38;5;124mstd\u001B[39m\u001B[38;5;124m'\u001B[39m, \u001B[38;5;124m'\u001B[39m\u001B[38;5;124mcount\u001B[39m\u001B[38;5;124m'\u001B[39m])[\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mfactor\u001B[39m\u001B[38;5;124m'\u001B[39m]\n\u001B[1;32m    191\u001B[0m     quantile_stats[\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mcount \u001B[39m\u001B[38;5;124m%\u001B[39m\u001B[38;5;124m'\u001B[39m] \u001B[38;5;241m=\u001B[39m quantile_stats[\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mcount\u001B[39m\u001B[38;5;124m'\u001B[39m] \\\n\u001B[1;32m    192\u001B[0m         \u001B[38;5;241m/\u001B[39m quantile_stats[\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mcount\u001B[39m\u001B[38;5;124m'\u001B[39m]\u001B[38;5;241m.\u001B[39msum() \u001B[38;5;241m*\u001B[39m \u001B[38;5;241m100.\u001B[39m\n\u001B[1;32m    194\u001B[0m     \u001B[38;5;28mprint\u001B[39m(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mQuantiles Statistics\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/groupby/generic.py:1432\u001B[0m, in \u001B[0;36mDataFrameGroupBy.aggregate\u001B[0;34m(self, func, engine, engine_kwargs, *args, **kwargs)\u001B[0m\n\u001B[1;32m   1429\u001B[0m     kwargs[\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mengine_kwargs\u001B[39m\u001B[38;5;124m\"\u001B[39m] \u001B[38;5;241m=\u001B[39m engine_kwargs\n\u001B[1;32m   1431\u001B[0m op \u001B[38;5;241m=\u001B[39m GroupByApply(\u001B[38;5;28mself\u001B[39m, func, args\u001B[38;5;241m=\u001B[39margs, kwargs\u001B[38;5;241m=\u001B[39mkwargs)\n\u001B[0;32m-> 1432\u001B[0m result \u001B[38;5;241m=\u001B[39m op\u001B[38;5;241m.\u001B[39magg()\n\u001B[1;32m   1433\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m is_dict_like(func) \u001B[38;5;129;01mand\u001B[39;00m result \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m:\n\u001B[1;32m   1434\u001B[0m     \u001B[38;5;66;03m# GH #52849\u001B[39;00m\n\u001B[1;32m   1435\u001B[0m     \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mas_index \u001B[38;5;129;01mand\u001B[39;00m is_list_like(func):\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/apply.py:193\u001B[0m, in \u001B[0;36mApply.agg\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m    190\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39magg_dict_like()\n\u001B[1;32m    191\u001B[0m \u001B[38;5;28;01melif\u001B[39;00m is_list_like(func):\n\u001B[1;32m    192\u001B[0m     \u001B[38;5;66;03m# we require a list, but not a 'str'\u001B[39;00m\n\u001B[0;32m--> 193\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39magg_list_like()\n\u001B[1;32m    195\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;28mcallable\u001B[39m(func):\n\u001B[1;32m    196\u001B[0m     f \u001B[38;5;241m=\u001B[39m com\u001B[38;5;241m.\u001B[39mget_cython_func(func)\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/apply.py:326\u001B[0m, in \u001B[0;36mApply.agg_list_like\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m    318\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21magg_list_like\u001B[39m(\u001B[38;5;28mself\u001B[39m) \u001B[38;5;241m-\u001B[39m\u001B[38;5;241m>\u001B[39m DataFrame \u001B[38;5;241m|\u001B[39m Series:\n\u001B[1;32m    319\u001B[0m \u001B[38;5;250m    \u001B[39m\u001B[38;5;124;03m\"\"\"\u001B[39;00m\n\u001B[1;32m    320\u001B[0m \u001B[38;5;124;03m    Compute aggregation in the case of a list-like argument.\u001B[39;00m\n\u001B[1;32m    321\u001B[0m \n\u001B[0;32m   (...)\u001B[0m\n\u001B[1;32m    324\u001B[0m \u001B[38;5;124;03m    Result of aggregation.\u001B[39;00m\n\u001B[1;32m    325\u001B[0m \u001B[38;5;124;03m    \"\"\"\u001B[39;00m\n\u001B[0;32m--> 326\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39magg_or_apply_list_like(op_name\u001B[38;5;241m=\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124magg\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/apply.py:1571\u001B[0m, in \u001B[0;36mGroupByApply.agg_or_apply_list_like\u001B[0;34m(self, op_name)\u001B[0m\n\u001B[1;32m   1566\u001B[0m \u001B[38;5;66;03m# Only set as_index=True on groupby objects, not Window or Resample\u001B[39;00m\n\u001B[1;32m   1567\u001B[0m \u001B[38;5;66;03m# that inherit from this class.\u001B[39;00m\n\u001B[1;32m   1568\u001B[0m \u001B[38;5;28;01mwith\u001B[39;00m com\u001B[38;5;241m.\u001B[39mtemp_setattr(\n\u001B[1;32m   1569\u001B[0m     obj, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mas_index\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;28;01mTrue\u001B[39;00m, condition\u001B[38;5;241m=\u001B[39m\u001B[38;5;28mhasattr\u001B[39m(obj, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mas_index\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n\u001B[1;32m   1570\u001B[0m ):\n\u001B[0;32m-> 1571\u001B[0m     keys, results \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mcompute_list_like(op_name, selected_obj, kwargs)\n\u001B[1;32m   1572\u001B[0m result \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mwrap_results_list_like(keys, results)\n\u001B[1;32m   1573\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m result\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/apply.py:385\u001B[0m, in \u001B[0;36mApply.compute_list_like\u001B[0;34m(self, op_name, selected_obj, kwargs)\u001B[0m\n\u001B[1;32m    379\u001B[0m colg \u001B[38;5;241m=\u001B[39m obj\u001B[38;5;241m.\u001B[39m_gotitem(col, ndim\u001B[38;5;241m=\u001B[39m\u001B[38;5;241m1\u001B[39m, subset\u001B[38;5;241m=\u001B[39mselected_obj\u001B[38;5;241m.\u001B[39miloc[:, index])\n\u001B[1;32m    380\u001B[0m args \u001B[38;5;241m=\u001B[39m (\n\u001B[1;32m    381\u001B[0m     [\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39maxis, \u001B[38;5;241m*\u001B[39m\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39margs]\n\u001B[1;32m    382\u001B[0m     \u001B[38;5;28;01mif\u001B[39;00m include_axis(op_name, colg)\n\u001B[1;32m    383\u001B[0m     \u001B[38;5;28;01melse\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39margs\n\u001B[1;32m    384\u001B[0m )\n\u001B[0;32m--> 385\u001B[0m new_res \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mgetattr\u001B[39m(colg, op_name)(func, \u001B[38;5;241m*\u001B[39margs, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n\u001B[1;32m    386\u001B[0m results\u001B[38;5;241m.\u001B[39mappend(new_res)\n\u001B[1;32m    387\u001B[0m indices\u001B[38;5;241m.\u001B[39mappend(index)\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/groupby/generic.py:257\u001B[0m, in \u001B[0;36mSeriesGroupBy.aggregate\u001B[0;34m(self, func, engine, engine_kwargs, *args, **kwargs)\u001B[0m\n\u001B[1;32m    255\u001B[0m kwargs[\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mengine\u001B[39m\u001B[38;5;124m\"\u001B[39m] \u001B[38;5;241m=\u001B[39m engine\n\u001B[1;32m    256\u001B[0m kwargs[\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mengine_kwargs\u001B[39m\u001B[38;5;124m\"\u001B[39m] \u001B[38;5;241m=\u001B[39m engine_kwargs\n\u001B[0;32m--> 257\u001B[0m ret \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_aggregate_multiple_funcs(func, \u001B[38;5;241m*\u001B[39margs, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n\u001B[1;32m    258\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m relabeling:\n\u001B[1;32m    259\u001B[0m     \u001B[38;5;66;03m# columns is not narrowed by mypy from relabeling flag\u001B[39;00m\n\u001B[1;32m    260\u001B[0m     \u001B[38;5;28;01massert\u001B[39;00m columns \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m  \u001B[38;5;66;03m# for mypy\u001B[39;00m\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/groupby/generic.py:362\u001B[0m, in \u001B[0;36mSeriesGroupBy._aggregate_multiple_funcs\u001B[0;34m(self, arg, *args, **kwargs)\u001B[0m\n\u001B[1;32m    360\u001B[0m     \u001B[38;5;28;01mfor\u001B[39;00m idx, (name, func) \u001B[38;5;129;01min\u001B[39;00m \u001B[38;5;28menumerate\u001B[39m(arg):\n\u001B[1;32m    361\u001B[0m         key \u001B[38;5;241m=\u001B[39m base\u001B[38;5;241m.\u001B[39mOutputKey(label\u001B[38;5;241m=\u001B[39mname, position\u001B[38;5;241m=\u001B[39midx)\n\u001B[0;32m--> 362\u001B[0m         results[key] \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39maggregate(func, \u001B[38;5;241m*\u001B[39margs, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n\u001B[1;32m    364\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;28many\u001B[39m(\u001B[38;5;28misinstance\u001B[39m(x, DataFrame) \u001B[38;5;28;01mfor\u001B[39;00m x \u001B[38;5;129;01min\u001B[39;00m results\u001B[38;5;241m.\u001B[39mvalues()):\n\u001B[1;32m    365\u001B[0m     \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01mpandas\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m concat\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/groupby/generic.py:249\u001B[0m, in \u001B[0;36mSeriesGroupBy.aggregate\u001B[0;34m(self, func, engine, engine_kwargs, *args, **kwargs)\u001B[0m\n\u001B[1;32m    247\u001B[0m     \u001B[38;5;28;01mif\u001B[39;00m engine_kwargs \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m:\n\u001B[1;32m    248\u001B[0m         kwargs[\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mengine_kwargs\u001B[39m\u001B[38;5;124m\"\u001B[39m] \u001B[38;5;241m=\u001B[39m engine_kwargs\n\u001B[0;32m--> 249\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mgetattr\u001B[39m(\u001B[38;5;28mself\u001B[39m, func)(\u001B[38;5;241m*\u001B[39margs, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n\u001B[1;32m    251\u001B[0m \u001B[38;5;28;01melif\u001B[39;00m \u001B[38;5;28misinstance\u001B[39m(func, abc\u001B[38;5;241m.\u001B[39mIterable):\n\u001B[1;32m    252\u001B[0m     \u001B[38;5;66;03m# Catch instances of lists / tuples\u001B[39;00m\n\u001B[1;32m    253\u001B[0m     \u001B[38;5;66;03m# but not the class list / tuple itself.\u001B[39;00m\n\u001B[1;32m    254\u001B[0m     func \u001B[38;5;241m=\u001B[39m maybe_mangle_lambdas(func)\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/groupby/groupby.py:3262\u001B[0m, in \u001B[0;36mGroupBy.min\u001B[0;34m(self, numeric_only, min_count, engine, engine_kwargs)\u001B[0m\n\u001B[1;32m   3254\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_numba_agg_general(\n\u001B[1;32m   3255\u001B[0m         grouped_min_max,\n\u001B[1;32m   3256\u001B[0m         executor\u001B[38;5;241m.\u001B[39midentity_dtype_mapping,\n\u001B[0;32m   (...)\u001B[0m\n\u001B[1;32m   3259\u001B[0m         is_max\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mFalse\u001B[39;00m,\n\u001B[1;32m   3260\u001B[0m     )\n\u001B[1;32m   3261\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[0;32m-> 3262\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_agg_general(\n\u001B[1;32m   3263\u001B[0m         numeric_only\u001B[38;5;241m=\u001B[39mnumeric_only,\n\u001B[1;32m   3264\u001B[0m         min_count\u001B[38;5;241m=\u001B[39mmin_count,\n\u001B[1;32m   3265\u001B[0m         alias\u001B[38;5;241m=\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mmin\u001B[39m\u001B[38;5;124m\"\u001B[39m,\n\u001B[1;32m   3266\u001B[0m         npfunc\u001B[38;5;241m=\u001B[39mnp\u001B[38;5;241m.\u001B[39mmin,\n\u001B[1;32m   3267\u001B[0m     )\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/groupby/groupby.py:1906\u001B[0m, in \u001B[0;36mGroupBy._agg_general\u001B[0;34m(self, numeric_only, min_count, alias, npfunc, **kwargs)\u001B[0m\n\u001B[1;32m   1896\u001B[0m \u001B[38;5;129m@final\u001B[39m\n\u001B[1;32m   1897\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21m_agg_general\u001B[39m(\n\u001B[1;32m   1898\u001B[0m     \u001B[38;5;28mself\u001B[39m,\n\u001B[0;32m   (...)\u001B[0m\n\u001B[1;32m   1904\u001B[0m     \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs,\n\u001B[1;32m   1905\u001B[0m ):\n\u001B[0;32m-> 1906\u001B[0m     result \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_cython_agg_general(\n\u001B[1;32m   1907\u001B[0m         how\u001B[38;5;241m=\u001B[39malias,\n\u001B[1;32m   1908\u001B[0m         alt\u001B[38;5;241m=\u001B[39mnpfunc,\n\u001B[1;32m   1909\u001B[0m         numeric_only\u001B[38;5;241m=\u001B[39mnumeric_only,\n\u001B[1;32m   1910\u001B[0m         min_count\u001B[38;5;241m=\u001B[39mmin_count,\n\u001B[1;32m   1911\u001B[0m         \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs,\n\u001B[1;32m   1912\u001B[0m     )\n\u001B[1;32m   1913\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m result\u001B[38;5;241m.\u001B[39m__finalize__(\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mobj, method\u001B[38;5;241m=\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mgroupby\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/groupby/groupby.py:1998\u001B[0m, in \u001B[0;36mGroupBy._cython_agg_general\u001B[0;34m(self, how, alt, numeric_only, min_count, **kwargs)\u001B[0m\n\u001B[1;32m   1995\u001B[0m     result \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_agg_py_fallback(how, values, ndim\u001B[38;5;241m=\u001B[39mdata\u001B[38;5;241m.\u001B[39mndim, alt\u001B[38;5;241m=\u001B[39malt)\n\u001B[1;32m   1996\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m result\n\u001B[0;32m-> 1998\u001B[0m new_mgr \u001B[38;5;241m=\u001B[39m data\u001B[38;5;241m.\u001B[39mgrouped_reduce(array_func)\n\u001B[1;32m   1999\u001B[0m res \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_wrap_agged_manager(new_mgr)\n\u001B[1;32m   2000\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m how \u001B[38;5;129;01min\u001B[39;00m [\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124midxmin\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124midxmax\u001B[39m\u001B[38;5;124m\"\u001B[39m]:\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/internals/base.py:367\u001B[0m, in \u001B[0;36mSingleDataManager.grouped_reduce\u001B[0;34m(self, func)\u001B[0m\n\u001B[1;32m    365\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mgrouped_reduce\u001B[39m(\u001B[38;5;28mself\u001B[39m, func):\n\u001B[1;32m    366\u001B[0m     arr \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39marray\n\u001B[0;32m--> 367\u001B[0m     res \u001B[38;5;241m=\u001B[39m func(arr)\n\u001B[1;32m    368\u001B[0m     index \u001B[38;5;241m=\u001B[39m default_index(\u001B[38;5;28mlen\u001B[39m(res))\n\u001B[1;32m    370\u001B[0m     mgr \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mtype\u001B[39m(\u001B[38;5;28mself\u001B[39m)\u001B[38;5;241m.\u001B[39mfrom_array(res, index)\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/groupby/groupby.py:1973\u001B[0m, in \u001B[0;36mGroupBy._cython_agg_general.<locals>.array_func\u001B[0;34m(values)\u001B[0m\n\u001B[1;32m   1971\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21marray_func\u001B[39m(values: ArrayLike) \u001B[38;5;241m-\u001B[39m\u001B[38;5;241m>\u001B[39m ArrayLike:\n\u001B[1;32m   1972\u001B[0m     \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[0;32m-> 1973\u001B[0m         result \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_grouper\u001B[38;5;241m.\u001B[39m_cython_operation(\n\u001B[1;32m   1974\u001B[0m             \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124maggregate\u001B[39m\u001B[38;5;124m\"\u001B[39m,\n\u001B[1;32m   1975\u001B[0m             values,\n\u001B[1;32m   1976\u001B[0m             how,\n\u001B[1;32m   1977\u001B[0m             axis\u001B[38;5;241m=\u001B[39mdata\u001B[38;5;241m.\u001B[39mndim \u001B[38;5;241m-\u001B[39m \u001B[38;5;241m1\u001B[39m,\n\u001B[1;32m   1978\u001B[0m             min_count\u001B[38;5;241m=\u001B[39mmin_count,\n\u001B[1;32m   1979\u001B[0m             \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs,\n\u001B[1;32m   1980\u001B[0m         )\n\u001B[1;32m   1981\u001B[0m     \u001B[38;5;28;01mexcept\u001B[39;00m \u001B[38;5;167;01mNotImplementedError\u001B[39;00m:\n\u001B[1;32m   1982\u001B[0m         \u001B[38;5;66;03m# generally if we have numeric_only=False\u001B[39;00m\n\u001B[1;32m   1983\u001B[0m         \u001B[38;5;66;03m# and non-applicable functions\u001B[39;00m\n\u001B[1;32m   1984\u001B[0m         \u001B[38;5;66;03m# try to python agg\u001B[39;00m\n\u001B[1;32m   1985\u001B[0m         \u001B[38;5;66;03m# TODO: shouldn't min_count matter?\u001B[39;00m\n\u001B[1;32m   1986\u001B[0m         \u001B[38;5;66;03m# TODO: avoid special casing SparseArray here\u001B[39;00m\n\u001B[1;32m   1987\u001B[0m         \u001B[38;5;28;01mif\u001B[39;00m how \u001B[38;5;129;01min\u001B[39;00m [\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124many\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mall\u001B[39m\u001B[38;5;124m\"\u001B[39m] \u001B[38;5;129;01mand\u001B[39;00m \u001B[38;5;28misinstance\u001B[39m(values, SparseArray):\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/groupby/ops.py:831\u001B[0m, in \u001B[0;36mBaseGrouper._cython_operation\u001B[0;34m(self, kind, values, how, axis, min_count, **kwargs)\u001B[0m\n\u001B[1;32m    829\u001B[0m ids, _, _ \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mgroup_info\n\u001B[1;32m    830\u001B[0m ngroups \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mngroups\n\u001B[0;32m--> 831\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m cy_op\u001B[38;5;241m.\u001B[39mcython_operation(\n\u001B[1;32m    832\u001B[0m     values\u001B[38;5;241m=\u001B[39mvalues,\n\u001B[1;32m    833\u001B[0m     axis\u001B[38;5;241m=\u001B[39maxis,\n\u001B[1;32m    834\u001B[0m     min_count\u001B[38;5;241m=\u001B[39mmin_count,\n\u001B[1;32m    835\u001B[0m     comp_ids\u001B[38;5;241m=\u001B[39mids,\n\u001B[1;32m    836\u001B[0m     ngroups\u001B[38;5;241m=\u001B[39mngroups,\n\u001B[1;32m    837\u001B[0m     \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs,\n\u001B[1;32m    838\u001B[0m )\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/groupby/ops.py:541\u001B[0m, in \u001B[0;36mWrappedCythonOp.cython_operation\u001B[0;34m(self, values, axis, min_count, comp_ids, ngroups, **kwargs)\u001B[0m\n\u001B[1;32m    537\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_validate_axis(axis, values)\n\u001B[1;32m    539\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28misinstance\u001B[39m(values, np\u001B[38;5;241m.\u001B[39mndarray):\n\u001B[1;32m    540\u001B[0m     \u001B[38;5;66;03m# i.e. ExtensionArray\u001B[39;00m\n\u001B[0;32m--> 541\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m values\u001B[38;5;241m.\u001B[39m_groupby_op(\n\u001B[1;32m    542\u001B[0m         how\u001B[38;5;241m=\u001B[39m\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mhow,\n\u001B[1;32m    543\u001B[0m         has_dropped_na\u001B[38;5;241m=\u001B[39m\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mhas_dropped_na,\n\u001B[1;32m    544\u001B[0m         min_count\u001B[38;5;241m=\u001B[39mmin_count,\n\u001B[1;32m    545\u001B[0m         ngroups\u001B[38;5;241m=\u001B[39mngroups,\n\u001B[1;32m    546\u001B[0m         ids\u001B[38;5;241m=\u001B[39mcomp_ids,\n\u001B[1;32m    547\u001B[0m         \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs,\n\u001B[1;32m    548\u001B[0m     )\n\u001B[1;32m    550\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_cython_op_ndim_compat(\n\u001B[1;32m    551\u001B[0m     values,\n\u001B[1;32m    552\u001B[0m     min_count\u001B[38;5;241m=\u001B[39mmin_count,\n\u001B[0;32m   (...)\u001B[0m\n\u001B[1;32m    556\u001B[0m     \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs,\n\u001B[1;32m    557\u001B[0m )\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/arrays/categorical.py:2726\u001B[0m, in \u001B[0;36mCategorical._groupby_op\u001B[0;34m(self, how, has_dropped_na, min_count, ngroups, ids, **kwargs)\u001B[0m\n\u001B[1;32m   2721\u001B[0m     \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mTypeError\u001B[39;00m(\u001B[38;5;124mf\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;132;01m{\u001B[39;00mdtype\u001B[38;5;132;01m}\u001B[39;00m\u001B[38;5;124m type does not support \u001B[39m\u001B[38;5;132;01m{\u001B[39;00mhow\u001B[38;5;132;01m}\u001B[39;00m\u001B[38;5;124m operations\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n\u001B[1;32m   2722\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m how \u001B[38;5;129;01min\u001B[39;00m [\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mmin\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mmax\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mrank\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124midxmin\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124midxmax\u001B[39m\u001B[38;5;124m\"\u001B[39m] \u001B[38;5;129;01mand\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m dtype\u001B[38;5;241m.\u001B[39mordered:\n\u001B[1;32m   2723\u001B[0m     \u001B[38;5;66;03m# raise TypeError instead of NotImplementedError to ensure we\u001B[39;00m\n\u001B[1;32m   2724\u001B[0m     \u001B[38;5;66;03m#  don't go down a group-by-group path, since in the empty-groups\u001B[39;00m\n\u001B[1;32m   2725\u001B[0m     \u001B[38;5;66;03m#  case that would fail to raise\u001B[39;00m\n\u001B[0;32m-> 2726\u001B[0m     \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mTypeError\u001B[39;00m(\u001B[38;5;124mf\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mCannot perform \u001B[39m\u001B[38;5;132;01m{\u001B[39;00mhow\u001B[38;5;132;01m}\u001B[39;00m\u001B[38;5;124m with non-ordered Categorical\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n\u001B[1;32m   2727\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m how \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;129;01min\u001B[39;00m [\n\u001B[1;32m   2728\u001B[0m     \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mrank\u001B[39m\u001B[38;5;124m\"\u001B[39m,\n\u001B[1;32m   2729\u001B[0m     \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124many\u001B[39m\u001B[38;5;124m\"\u001B[39m,\n\u001B[0;32m   (...)\u001B[0m\n\u001B[1;32m   2736\u001B[0m     \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124midxmax\u001B[39m\u001B[38;5;124m\"\u001B[39m,\n\u001B[1;32m   2737\u001B[0m ]:\n\u001B[1;32m   2738\u001B[0m     \u001B[38;5;28;01mif\u001B[39;00m kind \u001B[38;5;241m==\u001B[39m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mtransform\u001B[39m\u001B[38;5;124m\"\u001B[39m:\n",
      "\u001B[0;31mTypeError\u001B[0m: Cannot perform min with non-ordered Categorical"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 640x480 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "create_full_tear_sheet(factor_data, long_short=False, group_neutral=False, by_group=False)\n",
    "create_event_returns_tear_sheet(factor_data, prices, avgretplot=(3, 11),\n",
    "                                long_short=False, group_neutral=False, by_group=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "Cannot perform min with non-ordered Categorical",
     "output_type": "error",
     "traceback": [
      "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m",
      "\u001B[0;31mTypeError\u001B[0m                                 Traceback (most recent call last)",
      "Cell \u001B[0;32mIn[9], line 1\u001B[0m\n\u001B[0;32m----> 1\u001B[0m create_full_tear_sheet(factor_data, long_short\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mTrue\u001B[39;00m, group_neutral\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mFalse\u001B[39;00m, by_group\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mTrue\u001B[39;00m)\n\u001B[1;32m      2\u001B[0m create_event_returns_tear_sheet(factor_data, prices, avgretplot\u001B[38;5;241m=\u001B[39m(\u001B[38;5;241m3\u001B[39m, \u001B[38;5;241m11\u001B[39m),\n\u001B[1;32m      3\u001B[0m                                 long_short\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mTrue\u001B[39;00m, group_neutral\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mFalse\u001B[39;00m, by_group\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mTrue\u001B[39;00m)\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/alphalens/plotting.py:45\u001B[0m, in \u001B[0;36mcustomize.<locals>.call_w_context\u001B[0;34m(*args, **kwargs)\u001B[0m\n\u001B[1;32m     43\u001B[0m     \u001B[38;5;28;01mwith\u001B[39;00m plotting_context(), axes_style(), color_palette:\n\u001B[1;32m     44\u001B[0m         sns\u001B[38;5;241m.\u001B[39mdespine(left\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mTrue\u001B[39;00m)\n\u001B[0;32m---> 45\u001B[0m         \u001B[38;5;28;01mreturn\u001B[39;00m func(\u001B[38;5;241m*\u001B[39margs, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n\u001B[1;32m     46\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[1;32m     47\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m func(\u001B[38;5;241m*\u001B[39margs, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/alphalens/tears.py:528\u001B[0m, in \u001B[0;36mcreate_full_tear_sheet\u001B[0;34m(factor_data, long_short, group_neutral, by_group)\u001B[0m\n\u001B[1;32m    497\u001B[0m \u001B[38;5;129m@plotting\u001B[39m\u001B[38;5;241m.\u001B[39mcustomize\n\u001B[1;32m    498\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mcreate_full_tear_sheet\u001B[39m(factor_data,\n\u001B[1;32m    499\u001B[0m                            long_short\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mTrue\u001B[39;00m,\n\u001B[1;32m    500\u001B[0m                            group_neutral\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mFalse\u001B[39;00m,\n\u001B[1;32m    501\u001B[0m                            by_group\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mFalse\u001B[39;00m):\n\u001B[1;32m    502\u001B[0m \u001B[38;5;250m    \u001B[39m\u001B[38;5;124;03m\"\"\"\u001B[39;00m\n\u001B[1;32m    503\u001B[0m \u001B[38;5;124;03m    Creates a full tear sheet for analysis and evaluating single\u001B[39;00m\n\u001B[1;32m    504\u001B[0m \u001B[38;5;124;03m    return predicting (alpha) factor.\u001B[39;00m\n\u001B[0;32m   (...)\u001B[0m\n\u001B[1;32m    525\u001B[0m \u001B[38;5;124;03m        If True, display graphs separately for each group.\u001B[39;00m\n\u001B[1;32m    526\u001B[0m \u001B[38;5;124;03m    \"\"\"\u001B[39;00m\n\u001B[0;32m--> 528\u001B[0m     plotting\u001B[38;5;241m.\u001B[39mplot_quantile_statistics_table(factor_data)\n\u001B[1;32m    529\u001B[0m     create_returns_tear_sheet(\n\u001B[1;32m    530\u001B[0m         factor_data, long_short, group_neutral, by_group, set_context\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mFalse\u001B[39;00m\n\u001B[1;32m    531\u001B[0m     )\n\u001B[1;32m    532\u001B[0m     create_information_tear_sheet(\n\u001B[1;32m    533\u001B[0m         factor_data, group_neutral, by_group, set_context\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mFalse\u001B[39;00m\n\u001B[1;32m    534\u001B[0m     )\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/alphalens/plotting.py:190\u001B[0m, in \u001B[0;36mplot_quantile_statistics_table\u001B[0;34m(factor_data)\u001B[0m\n\u001B[1;32m    188\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mplot_quantile_statistics_table\u001B[39m(factor_data):\n\u001B[1;32m    189\u001B[0m     quantile_stats \u001B[38;5;241m=\u001B[39m factor_data\u001B[38;5;241m.\u001B[39mgroupby(\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mfactor_quantile\u001B[39m\u001B[38;5;124m'\u001B[39m) \\\n\u001B[0;32m--> 190\u001B[0m         \u001B[38;5;241m.\u001B[39magg([\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mmin\u001B[39m\u001B[38;5;124m'\u001B[39m, \u001B[38;5;124m'\u001B[39m\u001B[38;5;124mmax\u001B[39m\u001B[38;5;124m'\u001B[39m, \u001B[38;5;124m'\u001B[39m\u001B[38;5;124mmean\u001B[39m\u001B[38;5;124m'\u001B[39m, \u001B[38;5;124m'\u001B[39m\u001B[38;5;124mstd\u001B[39m\u001B[38;5;124m'\u001B[39m, \u001B[38;5;124m'\u001B[39m\u001B[38;5;124mcount\u001B[39m\u001B[38;5;124m'\u001B[39m])[\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mfactor\u001B[39m\u001B[38;5;124m'\u001B[39m]\n\u001B[1;32m    191\u001B[0m     quantile_stats[\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mcount \u001B[39m\u001B[38;5;124m%\u001B[39m\u001B[38;5;124m'\u001B[39m] \u001B[38;5;241m=\u001B[39m quantile_stats[\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mcount\u001B[39m\u001B[38;5;124m'\u001B[39m] \\\n\u001B[1;32m    192\u001B[0m         \u001B[38;5;241m/\u001B[39m quantile_stats[\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mcount\u001B[39m\u001B[38;5;124m'\u001B[39m]\u001B[38;5;241m.\u001B[39msum() \u001B[38;5;241m*\u001B[39m \u001B[38;5;241m100.\u001B[39m\n\u001B[1;32m    194\u001B[0m     \u001B[38;5;28mprint\u001B[39m(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mQuantiles Statistics\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/groupby/generic.py:1432\u001B[0m, in \u001B[0;36mDataFrameGroupBy.aggregate\u001B[0;34m(self, func, engine, engine_kwargs, *args, **kwargs)\u001B[0m\n\u001B[1;32m   1429\u001B[0m     kwargs[\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mengine_kwargs\u001B[39m\u001B[38;5;124m\"\u001B[39m] \u001B[38;5;241m=\u001B[39m engine_kwargs\n\u001B[1;32m   1431\u001B[0m op \u001B[38;5;241m=\u001B[39m GroupByApply(\u001B[38;5;28mself\u001B[39m, func, args\u001B[38;5;241m=\u001B[39margs, kwargs\u001B[38;5;241m=\u001B[39mkwargs)\n\u001B[0;32m-> 1432\u001B[0m result \u001B[38;5;241m=\u001B[39m op\u001B[38;5;241m.\u001B[39magg()\n\u001B[1;32m   1433\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m is_dict_like(func) \u001B[38;5;129;01mand\u001B[39;00m result \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m:\n\u001B[1;32m   1434\u001B[0m     \u001B[38;5;66;03m# GH #52849\u001B[39;00m\n\u001B[1;32m   1435\u001B[0m     \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mas_index \u001B[38;5;129;01mand\u001B[39;00m is_list_like(func):\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/apply.py:193\u001B[0m, in \u001B[0;36mApply.agg\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m    190\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39magg_dict_like()\n\u001B[1;32m    191\u001B[0m \u001B[38;5;28;01melif\u001B[39;00m is_list_like(func):\n\u001B[1;32m    192\u001B[0m     \u001B[38;5;66;03m# we require a list, but not a 'str'\u001B[39;00m\n\u001B[0;32m--> 193\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39magg_list_like()\n\u001B[1;32m    195\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;28mcallable\u001B[39m(func):\n\u001B[1;32m    196\u001B[0m     f \u001B[38;5;241m=\u001B[39m com\u001B[38;5;241m.\u001B[39mget_cython_func(func)\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/apply.py:326\u001B[0m, in \u001B[0;36mApply.agg_list_like\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m    318\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21magg_list_like\u001B[39m(\u001B[38;5;28mself\u001B[39m) \u001B[38;5;241m-\u001B[39m\u001B[38;5;241m>\u001B[39m DataFrame \u001B[38;5;241m|\u001B[39m Series:\n\u001B[1;32m    319\u001B[0m \u001B[38;5;250m    \u001B[39m\u001B[38;5;124;03m\"\"\"\u001B[39;00m\n\u001B[1;32m    320\u001B[0m \u001B[38;5;124;03m    Compute aggregation in the case of a list-like argument.\u001B[39;00m\n\u001B[1;32m    321\u001B[0m \n\u001B[0;32m   (...)\u001B[0m\n\u001B[1;32m    324\u001B[0m \u001B[38;5;124;03m    Result of aggregation.\u001B[39;00m\n\u001B[1;32m    325\u001B[0m \u001B[38;5;124;03m    \"\"\"\u001B[39;00m\n\u001B[0;32m--> 326\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39magg_or_apply_list_like(op_name\u001B[38;5;241m=\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124magg\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/apply.py:1571\u001B[0m, in \u001B[0;36mGroupByApply.agg_or_apply_list_like\u001B[0;34m(self, op_name)\u001B[0m\n\u001B[1;32m   1566\u001B[0m \u001B[38;5;66;03m# Only set as_index=True on groupby objects, not Window or Resample\u001B[39;00m\n\u001B[1;32m   1567\u001B[0m \u001B[38;5;66;03m# that inherit from this class.\u001B[39;00m\n\u001B[1;32m   1568\u001B[0m \u001B[38;5;28;01mwith\u001B[39;00m com\u001B[38;5;241m.\u001B[39mtemp_setattr(\n\u001B[1;32m   1569\u001B[0m     obj, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mas_index\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;28;01mTrue\u001B[39;00m, condition\u001B[38;5;241m=\u001B[39m\u001B[38;5;28mhasattr\u001B[39m(obj, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mas_index\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n\u001B[1;32m   1570\u001B[0m ):\n\u001B[0;32m-> 1571\u001B[0m     keys, results \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mcompute_list_like(op_name, selected_obj, kwargs)\n\u001B[1;32m   1572\u001B[0m result \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mwrap_results_list_like(keys, results)\n\u001B[1;32m   1573\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m result\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/apply.py:385\u001B[0m, in \u001B[0;36mApply.compute_list_like\u001B[0;34m(self, op_name, selected_obj, kwargs)\u001B[0m\n\u001B[1;32m    379\u001B[0m colg \u001B[38;5;241m=\u001B[39m obj\u001B[38;5;241m.\u001B[39m_gotitem(col, ndim\u001B[38;5;241m=\u001B[39m\u001B[38;5;241m1\u001B[39m, subset\u001B[38;5;241m=\u001B[39mselected_obj\u001B[38;5;241m.\u001B[39miloc[:, index])\n\u001B[1;32m    380\u001B[0m args \u001B[38;5;241m=\u001B[39m (\n\u001B[1;32m    381\u001B[0m     [\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39maxis, \u001B[38;5;241m*\u001B[39m\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39margs]\n\u001B[1;32m    382\u001B[0m     \u001B[38;5;28;01mif\u001B[39;00m include_axis(op_name, colg)\n\u001B[1;32m    383\u001B[0m     \u001B[38;5;28;01melse\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39margs\n\u001B[1;32m    384\u001B[0m )\n\u001B[0;32m--> 385\u001B[0m new_res \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mgetattr\u001B[39m(colg, op_name)(func, \u001B[38;5;241m*\u001B[39margs, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n\u001B[1;32m    386\u001B[0m results\u001B[38;5;241m.\u001B[39mappend(new_res)\n\u001B[1;32m    387\u001B[0m indices\u001B[38;5;241m.\u001B[39mappend(index)\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/groupby/generic.py:257\u001B[0m, in \u001B[0;36mSeriesGroupBy.aggregate\u001B[0;34m(self, func, engine, engine_kwargs, *args, **kwargs)\u001B[0m\n\u001B[1;32m    255\u001B[0m kwargs[\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mengine\u001B[39m\u001B[38;5;124m\"\u001B[39m] \u001B[38;5;241m=\u001B[39m engine\n\u001B[1;32m    256\u001B[0m kwargs[\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mengine_kwargs\u001B[39m\u001B[38;5;124m\"\u001B[39m] \u001B[38;5;241m=\u001B[39m engine_kwargs\n\u001B[0;32m--> 257\u001B[0m ret \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_aggregate_multiple_funcs(func, \u001B[38;5;241m*\u001B[39margs, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n\u001B[1;32m    258\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m relabeling:\n\u001B[1;32m    259\u001B[0m     \u001B[38;5;66;03m# columns is not narrowed by mypy from relabeling flag\u001B[39;00m\n\u001B[1;32m    260\u001B[0m     \u001B[38;5;28;01massert\u001B[39;00m columns \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m  \u001B[38;5;66;03m# for mypy\u001B[39;00m\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/groupby/generic.py:362\u001B[0m, in \u001B[0;36mSeriesGroupBy._aggregate_multiple_funcs\u001B[0;34m(self, arg, *args, **kwargs)\u001B[0m\n\u001B[1;32m    360\u001B[0m     \u001B[38;5;28;01mfor\u001B[39;00m idx, (name, func) \u001B[38;5;129;01min\u001B[39;00m \u001B[38;5;28menumerate\u001B[39m(arg):\n\u001B[1;32m    361\u001B[0m         key \u001B[38;5;241m=\u001B[39m base\u001B[38;5;241m.\u001B[39mOutputKey(label\u001B[38;5;241m=\u001B[39mname, position\u001B[38;5;241m=\u001B[39midx)\n\u001B[0;32m--> 362\u001B[0m         results[key] \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39maggregate(func, \u001B[38;5;241m*\u001B[39margs, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n\u001B[1;32m    364\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;28many\u001B[39m(\u001B[38;5;28misinstance\u001B[39m(x, DataFrame) \u001B[38;5;28;01mfor\u001B[39;00m x \u001B[38;5;129;01min\u001B[39;00m results\u001B[38;5;241m.\u001B[39mvalues()):\n\u001B[1;32m    365\u001B[0m     \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01mpandas\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m concat\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/groupby/generic.py:249\u001B[0m, in \u001B[0;36mSeriesGroupBy.aggregate\u001B[0;34m(self, func, engine, engine_kwargs, *args, **kwargs)\u001B[0m\n\u001B[1;32m    247\u001B[0m     \u001B[38;5;28;01mif\u001B[39;00m engine_kwargs \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m:\n\u001B[1;32m    248\u001B[0m         kwargs[\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mengine_kwargs\u001B[39m\u001B[38;5;124m\"\u001B[39m] \u001B[38;5;241m=\u001B[39m engine_kwargs\n\u001B[0;32m--> 249\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mgetattr\u001B[39m(\u001B[38;5;28mself\u001B[39m, func)(\u001B[38;5;241m*\u001B[39margs, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n\u001B[1;32m    251\u001B[0m \u001B[38;5;28;01melif\u001B[39;00m \u001B[38;5;28misinstance\u001B[39m(func, abc\u001B[38;5;241m.\u001B[39mIterable):\n\u001B[1;32m    252\u001B[0m     \u001B[38;5;66;03m# Catch instances of lists / tuples\u001B[39;00m\n\u001B[1;32m    253\u001B[0m     \u001B[38;5;66;03m# but not the class list / tuple itself.\u001B[39;00m\n\u001B[1;32m    254\u001B[0m     func \u001B[38;5;241m=\u001B[39m maybe_mangle_lambdas(func)\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/groupby/groupby.py:3262\u001B[0m, in \u001B[0;36mGroupBy.min\u001B[0;34m(self, numeric_only, min_count, engine, engine_kwargs)\u001B[0m\n\u001B[1;32m   3254\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_numba_agg_general(\n\u001B[1;32m   3255\u001B[0m         grouped_min_max,\n\u001B[1;32m   3256\u001B[0m         executor\u001B[38;5;241m.\u001B[39midentity_dtype_mapping,\n\u001B[0;32m   (...)\u001B[0m\n\u001B[1;32m   3259\u001B[0m         is_max\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mFalse\u001B[39;00m,\n\u001B[1;32m   3260\u001B[0m     )\n\u001B[1;32m   3261\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[0;32m-> 3262\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_agg_general(\n\u001B[1;32m   3263\u001B[0m         numeric_only\u001B[38;5;241m=\u001B[39mnumeric_only,\n\u001B[1;32m   3264\u001B[0m         min_count\u001B[38;5;241m=\u001B[39mmin_count,\n\u001B[1;32m   3265\u001B[0m         alias\u001B[38;5;241m=\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mmin\u001B[39m\u001B[38;5;124m\"\u001B[39m,\n\u001B[1;32m   3266\u001B[0m         npfunc\u001B[38;5;241m=\u001B[39mnp\u001B[38;5;241m.\u001B[39mmin,\n\u001B[1;32m   3267\u001B[0m     )\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/groupby/groupby.py:1906\u001B[0m, in \u001B[0;36mGroupBy._agg_general\u001B[0;34m(self, numeric_only, min_count, alias, npfunc, **kwargs)\u001B[0m\n\u001B[1;32m   1896\u001B[0m \u001B[38;5;129m@final\u001B[39m\n\u001B[1;32m   1897\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21m_agg_general\u001B[39m(\n\u001B[1;32m   1898\u001B[0m     \u001B[38;5;28mself\u001B[39m,\n\u001B[0;32m   (...)\u001B[0m\n\u001B[1;32m   1904\u001B[0m     \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs,\n\u001B[1;32m   1905\u001B[0m ):\n\u001B[0;32m-> 1906\u001B[0m     result \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_cython_agg_general(\n\u001B[1;32m   1907\u001B[0m         how\u001B[38;5;241m=\u001B[39malias,\n\u001B[1;32m   1908\u001B[0m         alt\u001B[38;5;241m=\u001B[39mnpfunc,\n\u001B[1;32m   1909\u001B[0m         numeric_only\u001B[38;5;241m=\u001B[39mnumeric_only,\n\u001B[1;32m   1910\u001B[0m         min_count\u001B[38;5;241m=\u001B[39mmin_count,\n\u001B[1;32m   1911\u001B[0m         \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs,\n\u001B[1;32m   1912\u001B[0m     )\n\u001B[1;32m   1913\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m result\u001B[38;5;241m.\u001B[39m__finalize__(\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mobj, method\u001B[38;5;241m=\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mgroupby\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/groupby/groupby.py:1998\u001B[0m, in \u001B[0;36mGroupBy._cython_agg_general\u001B[0;34m(self, how, alt, numeric_only, min_count, **kwargs)\u001B[0m\n\u001B[1;32m   1995\u001B[0m     result \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_agg_py_fallback(how, values, ndim\u001B[38;5;241m=\u001B[39mdata\u001B[38;5;241m.\u001B[39mndim, alt\u001B[38;5;241m=\u001B[39malt)\n\u001B[1;32m   1996\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m result\n\u001B[0;32m-> 1998\u001B[0m new_mgr \u001B[38;5;241m=\u001B[39m data\u001B[38;5;241m.\u001B[39mgrouped_reduce(array_func)\n\u001B[1;32m   1999\u001B[0m res \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_wrap_agged_manager(new_mgr)\n\u001B[1;32m   2000\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m how \u001B[38;5;129;01min\u001B[39;00m [\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124midxmin\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124midxmax\u001B[39m\u001B[38;5;124m\"\u001B[39m]:\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/internals/base.py:367\u001B[0m, in \u001B[0;36mSingleDataManager.grouped_reduce\u001B[0;34m(self, func)\u001B[0m\n\u001B[1;32m    365\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mgrouped_reduce\u001B[39m(\u001B[38;5;28mself\u001B[39m, func):\n\u001B[1;32m    366\u001B[0m     arr \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39marray\n\u001B[0;32m--> 367\u001B[0m     res \u001B[38;5;241m=\u001B[39m func(arr)\n\u001B[1;32m    368\u001B[0m     index \u001B[38;5;241m=\u001B[39m default_index(\u001B[38;5;28mlen\u001B[39m(res))\n\u001B[1;32m    370\u001B[0m     mgr \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mtype\u001B[39m(\u001B[38;5;28mself\u001B[39m)\u001B[38;5;241m.\u001B[39mfrom_array(res, index)\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/groupby/groupby.py:1973\u001B[0m, in \u001B[0;36mGroupBy._cython_agg_general.<locals>.array_func\u001B[0;34m(values)\u001B[0m\n\u001B[1;32m   1971\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21marray_func\u001B[39m(values: ArrayLike) \u001B[38;5;241m-\u001B[39m\u001B[38;5;241m>\u001B[39m ArrayLike:\n\u001B[1;32m   1972\u001B[0m     \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[0;32m-> 1973\u001B[0m         result \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_grouper\u001B[38;5;241m.\u001B[39m_cython_operation(\n\u001B[1;32m   1974\u001B[0m             \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124maggregate\u001B[39m\u001B[38;5;124m\"\u001B[39m,\n\u001B[1;32m   1975\u001B[0m             values,\n\u001B[1;32m   1976\u001B[0m             how,\n\u001B[1;32m   1977\u001B[0m             axis\u001B[38;5;241m=\u001B[39mdata\u001B[38;5;241m.\u001B[39mndim \u001B[38;5;241m-\u001B[39m \u001B[38;5;241m1\u001B[39m,\n\u001B[1;32m   1978\u001B[0m             min_count\u001B[38;5;241m=\u001B[39mmin_count,\n\u001B[1;32m   1979\u001B[0m             \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs,\n\u001B[1;32m   1980\u001B[0m         )\n\u001B[1;32m   1981\u001B[0m     \u001B[38;5;28;01mexcept\u001B[39;00m \u001B[38;5;167;01mNotImplementedError\u001B[39;00m:\n\u001B[1;32m   1982\u001B[0m         \u001B[38;5;66;03m# generally if we have numeric_only=False\u001B[39;00m\n\u001B[1;32m   1983\u001B[0m         \u001B[38;5;66;03m# and non-applicable functions\u001B[39;00m\n\u001B[1;32m   1984\u001B[0m         \u001B[38;5;66;03m# try to python agg\u001B[39;00m\n\u001B[1;32m   1985\u001B[0m         \u001B[38;5;66;03m# TODO: shouldn't min_count matter?\u001B[39;00m\n\u001B[1;32m   1986\u001B[0m         \u001B[38;5;66;03m# TODO: avoid special casing SparseArray here\u001B[39;00m\n\u001B[1;32m   1987\u001B[0m         \u001B[38;5;28;01mif\u001B[39;00m how \u001B[38;5;129;01min\u001B[39;00m [\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124many\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mall\u001B[39m\u001B[38;5;124m\"\u001B[39m] \u001B[38;5;129;01mand\u001B[39;00m \u001B[38;5;28misinstance\u001B[39m(values, SparseArray):\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/groupby/ops.py:831\u001B[0m, in \u001B[0;36mBaseGrouper._cython_operation\u001B[0;34m(self, kind, values, how, axis, min_count, **kwargs)\u001B[0m\n\u001B[1;32m    829\u001B[0m ids, _, _ \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mgroup_info\n\u001B[1;32m    830\u001B[0m ngroups \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mngroups\n\u001B[0;32m--> 831\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m cy_op\u001B[38;5;241m.\u001B[39mcython_operation(\n\u001B[1;32m    832\u001B[0m     values\u001B[38;5;241m=\u001B[39mvalues,\n\u001B[1;32m    833\u001B[0m     axis\u001B[38;5;241m=\u001B[39maxis,\n\u001B[1;32m    834\u001B[0m     min_count\u001B[38;5;241m=\u001B[39mmin_count,\n\u001B[1;32m    835\u001B[0m     comp_ids\u001B[38;5;241m=\u001B[39mids,\n\u001B[1;32m    836\u001B[0m     ngroups\u001B[38;5;241m=\u001B[39mngroups,\n\u001B[1;32m    837\u001B[0m     \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs,\n\u001B[1;32m    838\u001B[0m )\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/groupby/ops.py:541\u001B[0m, in \u001B[0;36mWrappedCythonOp.cython_operation\u001B[0;34m(self, values, axis, min_count, comp_ids, ngroups, **kwargs)\u001B[0m\n\u001B[1;32m    537\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_validate_axis(axis, values)\n\u001B[1;32m    539\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28misinstance\u001B[39m(values, np\u001B[38;5;241m.\u001B[39mndarray):\n\u001B[1;32m    540\u001B[0m     \u001B[38;5;66;03m# i.e. ExtensionArray\u001B[39;00m\n\u001B[0;32m--> 541\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m values\u001B[38;5;241m.\u001B[39m_groupby_op(\n\u001B[1;32m    542\u001B[0m         how\u001B[38;5;241m=\u001B[39m\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mhow,\n\u001B[1;32m    543\u001B[0m         has_dropped_na\u001B[38;5;241m=\u001B[39m\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mhas_dropped_na,\n\u001B[1;32m    544\u001B[0m         min_count\u001B[38;5;241m=\u001B[39mmin_count,\n\u001B[1;32m    545\u001B[0m         ngroups\u001B[38;5;241m=\u001B[39mngroups,\n\u001B[1;32m    546\u001B[0m         ids\u001B[38;5;241m=\u001B[39mcomp_ids,\n\u001B[1;32m    547\u001B[0m         \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs,\n\u001B[1;32m    548\u001B[0m     )\n\u001B[1;32m    550\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_cython_op_ndim_compat(\n\u001B[1;32m    551\u001B[0m     values,\n\u001B[1;32m    552\u001B[0m     min_count\u001B[38;5;241m=\u001B[39mmin_count,\n\u001B[0;32m   (...)\u001B[0m\n\u001B[1;32m    556\u001B[0m     \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs,\n\u001B[1;32m    557\u001B[0m )\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/arrays/categorical.py:2726\u001B[0m, in \u001B[0;36mCategorical._groupby_op\u001B[0;34m(self, how, has_dropped_na, min_count, ngroups, ids, **kwargs)\u001B[0m\n\u001B[1;32m   2721\u001B[0m     \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mTypeError\u001B[39;00m(\u001B[38;5;124mf\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;132;01m{\u001B[39;00mdtype\u001B[38;5;132;01m}\u001B[39;00m\u001B[38;5;124m type does not support \u001B[39m\u001B[38;5;132;01m{\u001B[39;00mhow\u001B[38;5;132;01m}\u001B[39;00m\u001B[38;5;124m operations\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n\u001B[1;32m   2722\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m how \u001B[38;5;129;01min\u001B[39;00m [\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mmin\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mmax\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mrank\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124midxmin\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124midxmax\u001B[39m\u001B[38;5;124m\"\u001B[39m] \u001B[38;5;129;01mand\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m dtype\u001B[38;5;241m.\u001B[39mordered:\n\u001B[1;32m   2723\u001B[0m     \u001B[38;5;66;03m# raise TypeError instead of NotImplementedError to ensure we\u001B[39;00m\n\u001B[1;32m   2724\u001B[0m     \u001B[38;5;66;03m#  don't go down a group-by-group path, since in the empty-groups\u001B[39;00m\n\u001B[1;32m   2725\u001B[0m     \u001B[38;5;66;03m#  case that would fail to raise\u001B[39;00m\n\u001B[0;32m-> 2726\u001B[0m     \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mTypeError\u001B[39;00m(\u001B[38;5;124mf\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mCannot perform \u001B[39m\u001B[38;5;132;01m{\u001B[39;00mhow\u001B[38;5;132;01m}\u001B[39;00m\u001B[38;5;124m with non-ordered Categorical\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n\u001B[1;32m   2727\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m how \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;129;01min\u001B[39;00m [\n\u001B[1;32m   2728\u001B[0m     \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mrank\u001B[39m\u001B[38;5;124m\"\u001B[39m,\n\u001B[1;32m   2729\u001B[0m     \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124many\u001B[39m\u001B[38;5;124m\"\u001B[39m,\n\u001B[0;32m   (...)\u001B[0m\n\u001B[1;32m   2736\u001B[0m     \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124midxmax\u001B[39m\u001B[38;5;124m\"\u001B[39m,\n\u001B[1;32m   2737\u001B[0m ]:\n\u001B[1;32m   2738\u001B[0m     \u001B[38;5;28;01mif\u001B[39;00m kind \u001B[38;5;241m==\u001B[39m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mtransform\u001B[39m\u001B[38;5;124m\"\u001B[39m:\n",
      "\u001B[0;31mTypeError\u001B[0m: Cannot perform min with non-ordered Categorical"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 640x480 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "create_full_tear_sheet(factor_data, long_short=True, group_neutral=False, by_group=True)\n",
    "create_event_returns_tear_sheet(factor_data, prices, avgretplot=(3, 11),\n",
    "                                long_short=True, group_neutral=False, by_group=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "Cannot perform min with non-ordered Categorical",
     "output_type": "error",
     "traceback": [
      "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m",
      "\u001B[0;31mTypeError\u001B[0m                                 Traceback (most recent call last)",
      "Cell \u001B[0;32mIn[10], line 1\u001B[0m\n\u001B[0;32m----> 1\u001B[0m create_full_tear_sheet(factor_data, long_short\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mTrue\u001B[39;00m, group_neutral\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mTrue\u001B[39;00m, by_group\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mTrue\u001B[39;00m)\n\u001B[1;32m      2\u001B[0m create_event_returns_tear_sheet(factor_data, prices, avgretplot\u001B[38;5;241m=\u001B[39m(\u001B[38;5;241m3\u001B[39m, \u001B[38;5;241m11\u001B[39m),\n\u001B[1;32m      3\u001B[0m                                 long_short\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mTrue\u001B[39;00m, group_neutral\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mTrue\u001B[39;00m, by_group\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mTrue\u001B[39;00m)\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/alphalens/plotting.py:45\u001B[0m, in \u001B[0;36mcustomize.<locals>.call_w_context\u001B[0;34m(*args, **kwargs)\u001B[0m\n\u001B[1;32m     43\u001B[0m     \u001B[38;5;28;01mwith\u001B[39;00m plotting_context(), axes_style(), color_palette:\n\u001B[1;32m     44\u001B[0m         sns\u001B[38;5;241m.\u001B[39mdespine(left\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mTrue\u001B[39;00m)\n\u001B[0;32m---> 45\u001B[0m         \u001B[38;5;28;01mreturn\u001B[39;00m func(\u001B[38;5;241m*\u001B[39margs, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n\u001B[1;32m     46\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[1;32m     47\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m func(\u001B[38;5;241m*\u001B[39margs, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/alphalens/tears.py:528\u001B[0m, in \u001B[0;36mcreate_full_tear_sheet\u001B[0;34m(factor_data, long_short, group_neutral, by_group)\u001B[0m\n\u001B[1;32m    497\u001B[0m \u001B[38;5;129m@plotting\u001B[39m\u001B[38;5;241m.\u001B[39mcustomize\n\u001B[1;32m    498\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mcreate_full_tear_sheet\u001B[39m(factor_data,\n\u001B[1;32m    499\u001B[0m                            long_short\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mTrue\u001B[39;00m,\n\u001B[1;32m    500\u001B[0m                            group_neutral\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mFalse\u001B[39;00m,\n\u001B[1;32m    501\u001B[0m                            by_group\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mFalse\u001B[39;00m):\n\u001B[1;32m    502\u001B[0m \u001B[38;5;250m    \u001B[39m\u001B[38;5;124;03m\"\"\"\u001B[39;00m\n\u001B[1;32m    503\u001B[0m \u001B[38;5;124;03m    Creates a full tear sheet for analysis and evaluating single\u001B[39;00m\n\u001B[1;32m    504\u001B[0m \u001B[38;5;124;03m    return predicting (alpha) factor.\u001B[39;00m\n\u001B[0;32m   (...)\u001B[0m\n\u001B[1;32m    525\u001B[0m \u001B[38;5;124;03m        If True, display graphs separately for each group.\u001B[39;00m\n\u001B[1;32m    526\u001B[0m \u001B[38;5;124;03m    \"\"\"\u001B[39;00m\n\u001B[0;32m--> 528\u001B[0m     plotting\u001B[38;5;241m.\u001B[39mplot_quantile_statistics_table(factor_data)\n\u001B[1;32m    529\u001B[0m     create_returns_tear_sheet(\n\u001B[1;32m    530\u001B[0m         factor_data, long_short, group_neutral, by_group, set_context\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mFalse\u001B[39;00m\n\u001B[1;32m    531\u001B[0m     )\n\u001B[1;32m    532\u001B[0m     create_information_tear_sheet(\n\u001B[1;32m    533\u001B[0m         factor_data, group_neutral, by_group, set_context\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mFalse\u001B[39;00m\n\u001B[1;32m    534\u001B[0m     )\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/alphalens/plotting.py:190\u001B[0m, in \u001B[0;36mplot_quantile_statistics_table\u001B[0;34m(factor_data)\u001B[0m\n\u001B[1;32m    188\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mplot_quantile_statistics_table\u001B[39m(factor_data):\n\u001B[1;32m    189\u001B[0m     quantile_stats \u001B[38;5;241m=\u001B[39m factor_data\u001B[38;5;241m.\u001B[39mgroupby(\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mfactor_quantile\u001B[39m\u001B[38;5;124m'\u001B[39m) \\\n\u001B[0;32m--> 190\u001B[0m         \u001B[38;5;241m.\u001B[39magg([\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mmin\u001B[39m\u001B[38;5;124m'\u001B[39m, \u001B[38;5;124m'\u001B[39m\u001B[38;5;124mmax\u001B[39m\u001B[38;5;124m'\u001B[39m, \u001B[38;5;124m'\u001B[39m\u001B[38;5;124mmean\u001B[39m\u001B[38;5;124m'\u001B[39m, \u001B[38;5;124m'\u001B[39m\u001B[38;5;124mstd\u001B[39m\u001B[38;5;124m'\u001B[39m, \u001B[38;5;124m'\u001B[39m\u001B[38;5;124mcount\u001B[39m\u001B[38;5;124m'\u001B[39m])[\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mfactor\u001B[39m\u001B[38;5;124m'\u001B[39m]\n\u001B[1;32m    191\u001B[0m     quantile_stats[\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mcount \u001B[39m\u001B[38;5;124m%\u001B[39m\u001B[38;5;124m'\u001B[39m] \u001B[38;5;241m=\u001B[39m quantile_stats[\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mcount\u001B[39m\u001B[38;5;124m'\u001B[39m] \\\n\u001B[1;32m    192\u001B[0m         \u001B[38;5;241m/\u001B[39m quantile_stats[\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mcount\u001B[39m\u001B[38;5;124m'\u001B[39m]\u001B[38;5;241m.\u001B[39msum() \u001B[38;5;241m*\u001B[39m \u001B[38;5;241m100.\u001B[39m\n\u001B[1;32m    194\u001B[0m     \u001B[38;5;28mprint\u001B[39m(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mQuantiles Statistics\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/groupby/generic.py:1432\u001B[0m, in \u001B[0;36mDataFrameGroupBy.aggregate\u001B[0;34m(self, func, engine, engine_kwargs, *args, **kwargs)\u001B[0m\n\u001B[1;32m   1429\u001B[0m     kwargs[\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mengine_kwargs\u001B[39m\u001B[38;5;124m\"\u001B[39m] \u001B[38;5;241m=\u001B[39m engine_kwargs\n\u001B[1;32m   1431\u001B[0m op \u001B[38;5;241m=\u001B[39m GroupByApply(\u001B[38;5;28mself\u001B[39m, func, args\u001B[38;5;241m=\u001B[39margs, kwargs\u001B[38;5;241m=\u001B[39mkwargs)\n\u001B[0;32m-> 1432\u001B[0m result \u001B[38;5;241m=\u001B[39m op\u001B[38;5;241m.\u001B[39magg()\n\u001B[1;32m   1433\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m is_dict_like(func) \u001B[38;5;129;01mand\u001B[39;00m result \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m:\n\u001B[1;32m   1434\u001B[0m     \u001B[38;5;66;03m# GH #52849\u001B[39;00m\n\u001B[1;32m   1435\u001B[0m     \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mas_index \u001B[38;5;129;01mand\u001B[39;00m is_list_like(func):\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/apply.py:193\u001B[0m, in \u001B[0;36mApply.agg\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m    190\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39magg_dict_like()\n\u001B[1;32m    191\u001B[0m \u001B[38;5;28;01melif\u001B[39;00m is_list_like(func):\n\u001B[1;32m    192\u001B[0m     \u001B[38;5;66;03m# we require a list, but not a 'str'\u001B[39;00m\n\u001B[0;32m--> 193\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39magg_list_like()\n\u001B[1;32m    195\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;28mcallable\u001B[39m(func):\n\u001B[1;32m    196\u001B[0m     f \u001B[38;5;241m=\u001B[39m com\u001B[38;5;241m.\u001B[39mget_cython_func(func)\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/apply.py:326\u001B[0m, in \u001B[0;36mApply.agg_list_like\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m    318\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21magg_list_like\u001B[39m(\u001B[38;5;28mself\u001B[39m) \u001B[38;5;241m-\u001B[39m\u001B[38;5;241m>\u001B[39m DataFrame \u001B[38;5;241m|\u001B[39m Series:\n\u001B[1;32m    319\u001B[0m \u001B[38;5;250m    \u001B[39m\u001B[38;5;124;03m\"\"\"\u001B[39;00m\n\u001B[1;32m    320\u001B[0m \u001B[38;5;124;03m    Compute aggregation in the case of a list-like argument.\u001B[39;00m\n\u001B[1;32m    321\u001B[0m \n\u001B[0;32m   (...)\u001B[0m\n\u001B[1;32m    324\u001B[0m \u001B[38;5;124;03m    Result of aggregation.\u001B[39;00m\n\u001B[1;32m    325\u001B[0m \u001B[38;5;124;03m    \"\"\"\u001B[39;00m\n\u001B[0;32m--> 326\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39magg_or_apply_list_like(op_name\u001B[38;5;241m=\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124magg\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/apply.py:1571\u001B[0m, in \u001B[0;36mGroupByApply.agg_or_apply_list_like\u001B[0;34m(self, op_name)\u001B[0m\n\u001B[1;32m   1566\u001B[0m \u001B[38;5;66;03m# Only set as_index=True on groupby objects, not Window or Resample\u001B[39;00m\n\u001B[1;32m   1567\u001B[0m \u001B[38;5;66;03m# that inherit from this class.\u001B[39;00m\n\u001B[1;32m   1568\u001B[0m \u001B[38;5;28;01mwith\u001B[39;00m com\u001B[38;5;241m.\u001B[39mtemp_setattr(\n\u001B[1;32m   1569\u001B[0m     obj, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mas_index\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;28;01mTrue\u001B[39;00m, condition\u001B[38;5;241m=\u001B[39m\u001B[38;5;28mhasattr\u001B[39m(obj, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mas_index\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n\u001B[1;32m   1570\u001B[0m ):\n\u001B[0;32m-> 1571\u001B[0m     keys, results \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mcompute_list_like(op_name, selected_obj, kwargs)\n\u001B[1;32m   1572\u001B[0m result \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mwrap_results_list_like(keys, results)\n\u001B[1;32m   1573\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m result\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/apply.py:385\u001B[0m, in \u001B[0;36mApply.compute_list_like\u001B[0;34m(self, op_name, selected_obj, kwargs)\u001B[0m\n\u001B[1;32m    379\u001B[0m colg \u001B[38;5;241m=\u001B[39m obj\u001B[38;5;241m.\u001B[39m_gotitem(col, ndim\u001B[38;5;241m=\u001B[39m\u001B[38;5;241m1\u001B[39m, subset\u001B[38;5;241m=\u001B[39mselected_obj\u001B[38;5;241m.\u001B[39miloc[:, index])\n\u001B[1;32m    380\u001B[0m args \u001B[38;5;241m=\u001B[39m (\n\u001B[1;32m    381\u001B[0m     [\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39maxis, \u001B[38;5;241m*\u001B[39m\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39margs]\n\u001B[1;32m    382\u001B[0m     \u001B[38;5;28;01mif\u001B[39;00m include_axis(op_name, colg)\n\u001B[1;32m    383\u001B[0m     \u001B[38;5;28;01melse\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39margs\n\u001B[1;32m    384\u001B[0m )\n\u001B[0;32m--> 385\u001B[0m new_res \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mgetattr\u001B[39m(colg, op_name)(func, \u001B[38;5;241m*\u001B[39margs, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n\u001B[1;32m    386\u001B[0m results\u001B[38;5;241m.\u001B[39mappend(new_res)\n\u001B[1;32m    387\u001B[0m indices\u001B[38;5;241m.\u001B[39mappend(index)\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/groupby/generic.py:257\u001B[0m, in \u001B[0;36mSeriesGroupBy.aggregate\u001B[0;34m(self, func, engine, engine_kwargs, *args, **kwargs)\u001B[0m\n\u001B[1;32m    255\u001B[0m kwargs[\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mengine\u001B[39m\u001B[38;5;124m\"\u001B[39m] \u001B[38;5;241m=\u001B[39m engine\n\u001B[1;32m    256\u001B[0m kwargs[\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mengine_kwargs\u001B[39m\u001B[38;5;124m\"\u001B[39m] \u001B[38;5;241m=\u001B[39m engine_kwargs\n\u001B[0;32m--> 257\u001B[0m ret \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_aggregate_multiple_funcs(func, \u001B[38;5;241m*\u001B[39margs, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n\u001B[1;32m    258\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m relabeling:\n\u001B[1;32m    259\u001B[0m     \u001B[38;5;66;03m# columns is not narrowed by mypy from relabeling flag\u001B[39;00m\n\u001B[1;32m    260\u001B[0m     \u001B[38;5;28;01massert\u001B[39;00m columns \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m  \u001B[38;5;66;03m# for mypy\u001B[39;00m\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/groupby/generic.py:362\u001B[0m, in \u001B[0;36mSeriesGroupBy._aggregate_multiple_funcs\u001B[0;34m(self, arg, *args, **kwargs)\u001B[0m\n\u001B[1;32m    360\u001B[0m     \u001B[38;5;28;01mfor\u001B[39;00m idx, (name, func) \u001B[38;5;129;01min\u001B[39;00m \u001B[38;5;28menumerate\u001B[39m(arg):\n\u001B[1;32m    361\u001B[0m         key \u001B[38;5;241m=\u001B[39m base\u001B[38;5;241m.\u001B[39mOutputKey(label\u001B[38;5;241m=\u001B[39mname, position\u001B[38;5;241m=\u001B[39midx)\n\u001B[0;32m--> 362\u001B[0m         results[key] \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39maggregate(func, \u001B[38;5;241m*\u001B[39margs, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n\u001B[1;32m    364\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;28many\u001B[39m(\u001B[38;5;28misinstance\u001B[39m(x, DataFrame) \u001B[38;5;28;01mfor\u001B[39;00m x \u001B[38;5;129;01min\u001B[39;00m results\u001B[38;5;241m.\u001B[39mvalues()):\n\u001B[1;32m    365\u001B[0m     \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01mpandas\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m concat\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/groupby/generic.py:249\u001B[0m, in \u001B[0;36mSeriesGroupBy.aggregate\u001B[0;34m(self, func, engine, engine_kwargs, *args, **kwargs)\u001B[0m\n\u001B[1;32m    247\u001B[0m     \u001B[38;5;28;01mif\u001B[39;00m engine_kwargs \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m:\n\u001B[1;32m    248\u001B[0m         kwargs[\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mengine_kwargs\u001B[39m\u001B[38;5;124m\"\u001B[39m] \u001B[38;5;241m=\u001B[39m engine_kwargs\n\u001B[0;32m--> 249\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mgetattr\u001B[39m(\u001B[38;5;28mself\u001B[39m, func)(\u001B[38;5;241m*\u001B[39margs, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n\u001B[1;32m    251\u001B[0m \u001B[38;5;28;01melif\u001B[39;00m \u001B[38;5;28misinstance\u001B[39m(func, abc\u001B[38;5;241m.\u001B[39mIterable):\n\u001B[1;32m    252\u001B[0m     \u001B[38;5;66;03m# Catch instances of lists / tuples\u001B[39;00m\n\u001B[1;32m    253\u001B[0m     \u001B[38;5;66;03m# but not the class list / tuple itself.\u001B[39;00m\n\u001B[1;32m    254\u001B[0m     func \u001B[38;5;241m=\u001B[39m maybe_mangle_lambdas(func)\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/groupby/groupby.py:3262\u001B[0m, in \u001B[0;36mGroupBy.min\u001B[0;34m(self, numeric_only, min_count, engine, engine_kwargs)\u001B[0m\n\u001B[1;32m   3254\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_numba_agg_general(\n\u001B[1;32m   3255\u001B[0m         grouped_min_max,\n\u001B[1;32m   3256\u001B[0m         executor\u001B[38;5;241m.\u001B[39midentity_dtype_mapping,\n\u001B[0;32m   (...)\u001B[0m\n\u001B[1;32m   3259\u001B[0m         is_max\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mFalse\u001B[39;00m,\n\u001B[1;32m   3260\u001B[0m     )\n\u001B[1;32m   3261\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[0;32m-> 3262\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_agg_general(\n\u001B[1;32m   3263\u001B[0m         numeric_only\u001B[38;5;241m=\u001B[39mnumeric_only,\n\u001B[1;32m   3264\u001B[0m         min_count\u001B[38;5;241m=\u001B[39mmin_count,\n\u001B[1;32m   3265\u001B[0m         alias\u001B[38;5;241m=\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mmin\u001B[39m\u001B[38;5;124m\"\u001B[39m,\n\u001B[1;32m   3266\u001B[0m         npfunc\u001B[38;5;241m=\u001B[39mnp\u001B[38;5;241m.\u001B[39mmin,\n\u001B[1;32m   3267\u001B[0m     )\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/groupby/groupby.py:1906\u001B[0m, in \u001B[0;36mGroupBy._agg_general\u001B[0;34m(self, numeric_only, min_count, alias, npfunc, **kwargs)\u001B[0m\n\u001B[1;32m   1896\u001B[0m \u001B[38;5;129m@final\u001B[39m\n\u001B[1;32m   1897\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21m_agg_general\u001B[39m(\n\u001B[1;32m   1898\u001B[0m     \u001B[38;5;28mself\u001B[39m,\n\u001B[0;32m   (...)\u001B[0m\n\u001B[1;32m   1904\u001B[0m     \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs,\n\u001B[1;32m   1905\u001B[0m ):\n\u001B[0;32m-> 1906\u001B[0m     result \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_cython_agg_general(\n\u001B[1;32m   1907\u001B[0m         how\u001B[38;5;241m=\u001B[39malias,\n\u001B[1;32m   1908\u001B[0m         alt\u001B[38;5;241m=\u001B[39mnpfunc,\n\u001B[1;32m   1909\u001B[0m         numeric_only\u001B[38;5;241m=\u001B[39mnumeric_only,\n\u001B[1;32m   1910\u001B[0m         min_count\u001B[38;5;241m=\u001B[39mmin_count,\n\u001B[1;32m   1911\u001B[0m         \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs,\n\u001B[1;32m   1912\u001B[0m     )\n\u001B[1;32m   1913\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m result\u001B[38;5;241m.\u001B[39m__finalize__(\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mobj, method\u001B[38;5;241m=\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mgroupby\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/groupby/groupby.py:1998\u001B[0m, in \u001B[0;36mGroupBy._cython_agg_general\u001B[0;34m(self, how, alt, numeric_only, min_count, **kwargs)\u001B[0m\n\u001B[1;32m   1995\u001B[0m     result \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_agg_py_fallback(how, values, ndim\u001B[38;5;241m=\u001B[39mdata\u001B[38;5;241m.\u001B[39mndim, alt\u001B[38;5;241m=\u001B[39malt)\n\u001B[1;32m   1996\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m result\n\u001B[0;32m-> 1998\u001B[0m new_mgr \u001B[38;5;241m=\u001B[39m data\u001B[38;5;241m.\u001B[39mgrouped_reduce(array_func)\n\u001B[1;32m   1999\u001B[0m res \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_wrap_agged_manager(new_mgr)\n\u001B[1;32m   2000\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m how \u001B[38;5;129;01min\u001B[39;00m [\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124midxmin\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124midxmax\u001B[39m\u001B[38;5;124m\"\u001B[39m]:\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/internals/base.py:367\u001B[0m, in \u001B[0;36mSingleDataManager.grouped_reduce\u001B[0;34m(self, func)\u001B[0m\n\u001B[1;32m    365\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mgrouped_reduce\u001B[39m(\u001B[38;5;28mself\u001B[39m, func):\n\u001B[1;32m    366\u001B[0m     arr \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39marray\n\u001B[0;32m--> 367\u001B[0m     res \u001B[38;5;241m=\u001B[39m func(arr)\n\u001B[1;32m    368\u001B[0m     index \u001B[38;5;241m=\u001B[39m default_index(\u001B[38;5;28mlen\u001B[39m(res))\n\u001B[1;32m    370\u001B[0m     mgr \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mtype\u001B[39m(\u001B[38;5;28mself\u001B[39m)\u001B[38;5;241m.\u001B[39mfrom_array(res, index)\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/groupby/groupby.py:1973\u001B[0m, in \u001B[0;36mGroupBy._cython_agg_general.<locals>.array_func\u001B[0;34m(values)\u001B[0m\n\u001B[1;32m   1971\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21marray_func\u001B[39m(values: ArrayLike) \u001B[38;5;241m-\u001B[39m\u001B[38;5;241m>\u001B[39m ArrayLike:\n\u001B[1;32m   1972\u001B[0m     \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[0;32m-> 1973\u001B[0m         result \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_grouper\u001B[38;5;241m.\u001B[39m_cython_operation(\n\u001B[1;32m   1974\u001B[0m             \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124maggregate\u001B[39m\u001B[38;5;124m\"\u001B[39m,\n\u001B[1;32m   1975\u001B[0m             values,\n\u001B[1;32m   1976\u001B[0m             how,\n\u001B[1;32m   1977\u001B[0m             axis\u001B[38;5;241m=\u001B[39mdata\u001B[38;5;241m.\u001B[39mndim \u001B[38;5;241m-\u001B[39m \u001B[38;5;241m1\u001B[39m,\n\u001B[1;32m   1978\u001B[0m             min_count\u001B[38;5;241m=\u001B[39mmin_count,\n\u001B[1;32m   1979\u001B[0m             \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs,\n\u001B[1;32m   1980\u001B[0m         )\n\u001B[1;32m   1981\u001B[0m     \u001B[38;5;28;01mexcept\u001B[39;00m \u001B[38;5;167;01mNotImplementedError\u001B[39;00m:\n\u001B[1;32m   1982\u001B[0m         \u001B[38;5;66;03m# generally if we have numeric_only=False\u001B[39;00m\n\u001B[1;32m   1983\u001B[0m         \u001B[38;5;66;03m# and non-applicable functions\u001B[39;00m\n\u001B[1;32m   1984\u001B[0m         \u001B[38;5;66;03m# try to python agg\u001B[39;00m\n\u001B[1;32m   1985\u001B[0m         \u001B[38;5;66;03m# TODO: shouldn't min_count matter?\u001B[39;00m\n\u001B[1;32m   1986\u001B[0m         \u001B[38;5;66;03m# TODO: avoid special casing SparseArray here\u001B[39;00m\n\u001B[1;32m   1987\u001B[0m         \u001B[38;5;28;01mif\u001B[39;00m how \u001B[38;5;129;01min\u001B[39;00m [\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124many\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mall\u001B[39m\u001B[38;5;124m\"\u001B[39m] \u001B[38;5;129;01mand\u001B[39;00m \u001B[38;5;28misinstance\u001B[39m(values, SparseArray):\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/groupby/ops.py:831\u001B[0m, in \u001B[0;36mBaseGrouper._cython_operation\u001B[0;34m(self, kind, values, how, axis, min_count, **kwargs)\u001B[0m\n\u001B[1;32m    829\u001B[0m ids, _, _ \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mgroup_info\n\u001B[1;32m    830\u001B[0m ngroups \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mngroups\n\u001B[0;32m--> 831\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m cy_op\u001B[38;5;241m.\u001B[39mcython_operation(\n\u001B[1;32m    832\u001B[0m     values\u001B[38;5;241m=\u001B[39mvalues,\n\u001B[1;32m    833\u001B[0m     axis\u001B[38;5;241m=\u001B[39maxis,\n\u001B[1;32m    834\u001B[0m     min_count\u001B[38;5;241m=\u001B[39mmin_count,\n\u001B[1;32m    835\u001B[0m     comp_ids\u001B[38;5;241m=\u001B[39mids,\n\u001B[1;32m    836\u001B[0m     ngroups\u001B[38;5;241m=\u001B[39mngroups,\n\u001B[1;32m    837\u001B[0m     \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs,\n\u001B[1;32m    838\u001B[0m )\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/groupby/ops.py:541\u001B[0m, in \u001B[0;36mWrappedCythonOp.cython_operation\u001B[0;34m(self, values, axis, min_count, comp_ids, ngroups, **kwargs)\u001B[0m\n\u001B[1;32m    537\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_validate_axis(axis, values)\n\u001B[1;32m    539\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28misinstance\u001B[39m(values, np\u001B[38;5;241m.\u001B[39mndarray):\n\u001B[1;32m    540\u001B[0m     \u001B[38;5;66;03m# i.e. ExtensionArray\u001B[39;00m\n\u001B[0;32m--> 541\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m values\u001B[38;5;241m.\u001B[39m_groupby_op(\n\u001B[1;32m    542\u001B[0m         how\u001B[38;5;241m=\u001B[39m\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mhow,\n\u001B[1;32m    543\u001B[0m         has_dropped_na\u001B[38;5;241m=\u001B[39m\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mhas_dropped_na,\n\u001B[1;32m    544\u001B[0m         min_count\u001B[38;5;241m=\u001B[39mmin_count,\n\u001B[1;32m    545\u001B[0m         ngroups\u001B[38;5;241m=\u001B[39mngroups,\n\u001B[1;32m    546\u001B[0m         ids\u001B[38;5;241m=\u001B[39mcomp_ids,\n\u001B[1;32m    547\u001B[0m         \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs,\n\u001B[1;32m    548\u001B[0m     )\n\u001B[1;32m    550\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_cython_op_ndim_compat(\n\u001B[1;32m    551\u001B[0m     values,\n\u001B[1;32m    552\u001B[0m     min_count\u001B[38;5;241m=\u001B[39mmin_count,\n\u001B[0;32m   (...)\u001B[0m\n\u001B[1;32m    556\u001B[0m     \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs,\n\u001B[1;32m    557\u001B[0m )\n",
      "File \u001B[0;32m~/opt/anaconda3/lib/python3.11/site-packages/pandas/core/arrays/categorical.py:2726\u001B[0m, in \u001B[0;36mCategorical._groupby_op\u001B[0;34m(self, how, has_dropped_na, min_count, ngroups, ids, **kwargs)\u001B[0m\n\u001B[1;32m   2721\u001B[0m     \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mTypeError\u001B[39;00m(\u001B[38;5;124mf\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;132;01m{\u001B[39;00mdtype\u001B[38;5;132;01m}\u001B[39;00m\u001B[38;5;124m type does not support \u001B[39m\u001B[38;5;132;01m{\u001B[39;00mhow\u001B[38;5;132;01m}\u001B[39;00m\u001B[38;5;124m operations\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n\u001B[1;32m   2722\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m how \u001B[38;5;129;01min\u001B[39;00m [\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mmin\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mmax\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mrank\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124midxmin\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124midxmax\u001B[39m\u001B[38;5;124m\"\u001B[39m] \u001B[38;5;129;01mand\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m dtype\u001B[38;5;241m.\u001B[39mordered:\n\u001B[1;32m   2723\u001B[0m     \u001B[38;5;66;03m# raise TypeError instead of NotImplementedError to ensure we\u001B[39;00m\n\u001B[1;32m   2724\u001B[0m     \u001B[38;5;66;03m#  don't go down a group-by-group path, since in the empty-groups\u001B[39;00m\n\u001B[1;32m   2725\u001B[0m     \u001B[38;5;66;03m#  case that would fail to raise\u001B[39;00m\n\u001B[0;32m-> 2726\u001B[0m     \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mTypeError\u001B[39;00m(\u001B[38;5;124mf\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mCannot perform \u001B[39m\u001B[38;5;132;01m{\u001B[39;00mhow\u001B[38;5;132;01m}\u001B[39;00m\u001B[38;5;124m with non-ordered Categorical\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n\u001B[1;32m   2727\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m how \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;129;01min\u001B[39;00m [\n\u001B[1;32m   2728\u001B[0m     \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mrank\u001B[39m\u001B[38;5;124m\"\u001B[39m,\n\u001B[1;32m   2729\u001B[0m     \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124many\u001B[39m\u001B[38;5;124m\"\u001B[39m,\n\u001B[0;32m   (...)\u001B[0m\n\u001B[1;32m   2736\u001B[0m     \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124midxmax\u001B[39m\u001B[38;5;124m\"\u001B[39m,\n\u001B[1;32m   2737\u001B[0m ]:\n\u001B[1;32m   2738\u001B[0m     \u001B[38;5;28;01mif\u001B[39;00m kind \u001B[38;5;241m==\u001B[39m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mtransform\u001B[39m\u001B[38;5;124m\"\u001B[39m:\n",
      "\u001B[0;31mTypeError\u001B[0m: Cannot perform min with non-ordered Categorical"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 640x480 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "create_full_tear_sheet(factor_data, long_short=True, group_neutral=True, by_group=True)\n",
    "create_event_returns_tear_sheet(factor_data, prices, avgretplot=(3, 11),\n",
    "                                long_short=True, group_neutral=True, by_group=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
